#ifndef __SECURITY__
#define __SECURITY__

#include "stdlib.h"

#define SHA256_HASH_SIZE        32  // SHA256 outputs a 32 byte digest
#define SHA256_BLOCK_SIZE       64  // SHA256处理的块大小

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;

// 初始化安全图片签名接口
// @appName SDK运行时对应的appName
// @secureJpgBytes 安全图片字节数组
// @jpgSize 安全图片的长度
// @appIdBuf [out] 接收AppId的缓冲区
// @bufSize 接收AppId的缓冲区长度
// @return 小于0：错误编码，大于0: 输出appId的长度。也可以通过strlen读取长度
int initWithSecurityJpg(const char* appName, char *secureJpgBytes, int jpgSize,
    char* appIdBuf, int bufSize);

// 从安全图片中读取AppId，需要先经过初始化
// @return appId. 不需要释放内存. NULL表示接口未初始化或初始化没成功
char * getAppIdFromSecurityJpg(void);


// 利用安全图片中的信息进行签名
// @toSign 需要签名的明文字节数组
// @size   需要签名的明文长度
// @signatureBuffer 保存签名(base64)的缓冲区. 需要在外部分配。一般分配64字节就足够了
// @bufSize 缓冲区的长度
// @return 签名长度；小于0：错误编码
int signWithSecurityJpg(const char *toSign, int size, char *signatureBuffer, int bufSize);

//-----------------------------------------------------------------------
//  sha256
//-----------------------------------------------------------------------

typedef struct SHA256_CTX {
  uint8_t data[64]; // current 512-bit chunk of message data, just like a buffer
  uint32_t datalen;  // sign the data length of current chunk
  unsigned long long bitlen; // the bit length of the total message
  uint32_t state[8];         // store the middle state of hash abstract
} sha256_ctx;

// sha256接口函数
void sha256_init(sha256_ctx *ctx);

// sha256分段处理接口
void sha256_update(sha256_ctx *ctx, const uint8_t data[], size_t len);

// 输出sha256 hash
// @hash_out [out] 输出缓冲区，长度必须大于SHA256_HASH_SIZE
void sha256_final(sha256_ctx *ctx, uint8_t digest[SHA256_HASH_SIZE]);

// sha256一次性Hash接口
// @hash_out [out] 输出缓冲区，长度必须大于SHA256_HASH_SIZE
void sha256(const uint8_t *data, int data_len,uint8_t digest[SHA256_HASH_SIZE]);


//-----------------------------------------------------------------------
//  hmac-sha256
//-----------------------------------------------------------------------

typedef struct HMAC_SHA256_CTX {
  uint8_t o_key_pad[SHA256_BLOCK_SIZE]; // key padding

  sha256_ctx sha256_ctx;
} hmac_sha256_ctx;

// hmac-sha256分段处理接口
void hmac_sha256_init(hmac_sha256_ctx *ctx, const uint8_t *key, int key_len);

void hmac_sha256_update(hmac_sha256_ctx *ctx, const uint8_t data[], size_t len);

void hmac_sha256_final(hmac_sha256_ctx *ctx, uint8_t hash_out[SHA256_HASH_SIZE]);

// 实现hmac-sha256一次性hash接口
// @out [out]  输出缓冲区，长度必须大于SHA256_HASH_SIZE
void hmac_sha256(const uint8_t *data, size_t len, const uint8_t *key, int key_len, uint8_t out[SHA256_HASH_SIZE]);

// 实现hmac-sha256验签
// @return 0 验签成功，其他错误编码
int hmac_sha256_sign_verify(const uint8_t *signature, const uint8_t *data, size_t len, const uint8_t *key, int key_len);


//-----------------------------------------------------------------------
//  base64
//-----------------------------------------------------------------------

#define BASE64_ENCODE_OUT_SIZE(s)    ((((s) + 2) / 3 * 4) + 1)  // +2是为了保证向上取整, +1保证字符串'\0'结尾
#define BASE64_DECODE_OUT_SIZE(s)    (((s)) / 4 * 3)

// 对输入的进行base64编码并输出到out中
// @in:     需要编码的内容
// @inlen:  需要编码的内容长度
// @out:    [out] 输出的buffer. 分配buffer时可以用BASE64_ENCODE_OUT_SIZE计算(比编码字符串长度+1来保存'\0')
// @return: 返回编码出来字符串的长度，不包括'\0'
int imi_base64_encode(const char *in, int inlen, char *out);

// 对输入的进行base64编码, 并通过out输出
// @in:     需要编码的内容
// @inlen:  需要编码的内容长度
// @out:    [out] 输出的buffer, 内存将在内部分配. 调用者需要自己释放
// @return: 返回编码出来字符串的长度，包括'\0'
int imi_base64_encode_new(const char *in, int inlen, char **out);

// 对输入的base64字符串解码并输出到out中
// @in:     需要解码的字符串
// @out:    [out] 输出的buffer
// @return: 返回解码出来的内容长度
int imi_base64_decode(const char *in, char *out);

// 对输入的base64字符串解码并输出到out中
// @in:     需要解码的字符串
// @out:    [out] 输出的buffer, 内存将在内部分配. 调用者需要自己释放
// @return: 返回解码出来的内容长度
int imi_base64_decode_new(const char *in, char **out);


#endif // __SECURITY__
